package tok

// 为了分析如下的自定义规则代码：
/**
let five = 5;
let ten = 10;

let add = fn(x, y) {
  x + y;
};

let result = add(five, ten);
*/

// 词法分析要基于一个又一个的单元，这些单元称之为 token
// 这些token包括 标识符(或者说变量名)、字面量(整数或者字符串及其值)、运算符(加减乘除)、分隔符(空格逗号或者分号)、关键字(fn/let之类的)
const (
	// 定义几种词法单元的类型
	// 1. 标识符
	IDENT = "IDENTITY" // 其实就是变量名，比如five/ten/add/result
	// 2. 字面量的各种类型
	INT   = "INT"
	STR   = "STRING"
	TRUE  = "TRUE"
	FALSE = "FALSE"
	// 3. 运算符
	ASSIGN = "="
	PLUS   = "+"
	SUB    = "-"
	MULTI  = "*" // 该符号不仅表示“乘”的意思，还有可能表示多行注释“/*”中的。
	DIVIDE = "/"
	BANG   = "!" // 逻辑非
	SLASH  = "/"
	LT     = "<"
	GT     = ">"
	EQUAL  = "=="
	NOT_EQ = "!="
	// 4. 分隔符
	COMMA     = "," // 逗号
	LPAREN    = "(" // 左圆括号 parenthesis表示圆括号的意思
	RPAREN    = ")" // 左圆括号
	LBRACE    = "{" // 左大括号 brace 是大括号的意思
	RBRACE    = "}"
	SEMICOLON = ";"
	LBRACKET  = "[" // 表示数组的左中括号
	RBRACKET  = "]"
	COLON     = ":"
	// 5. 关键字
	FUNCTION = "FUNCTION"
	LET      = "LET"
	IF       = "IF"
	ELSE     = "ELSE"
	RETURN   = "RETURN"
	// 6. 其他元数据单元 - 可能用于控制流程的token
	ILLEGAL = "ILLEGAL"
	EOF     = "EOF"
)

// 如下定义token结构

type TokenType string // 其实感觉用int8定义一个枚举值更贴切一些，暂时先按照书本上来
type Token struct {
	Type    TokenType // 存储词法单元的类型，比如类型是 IDENTITY
	Literal string    // 存储词法单元的值，比如IDENTITY也就是标识符类型的词法单元，他的值如果是 result，也就是说当前词法单元是一个名字叫做result的变量名
}

// 关键字 类型的词法单元的列表
var keywords = map[string]TokenType{
	"fn":     FUNCTION,
	"let":    LET,
	"if":     IF,
	"else":   ELSE,
	"return": RETURN,
}

// 类型系统的词法单元
var typeSystem = map[string]TokenType{
	"true":  TRUE,
	"false": FALSE,
}

func AnalyzeWordTokenType(identifier string) TokenType {
	// 如果是关键字的话，返回对应的词法单元类型
	if kind, ok := keywords[identifier]; ok {
		return kind
	}
	// 如果是类型系统的话，返回对应的词法单元类型
	if kind, ok := typeSystem[identifier]; ok {
		return kind
	}
	// 不是关键字一律视为是标识符类型(变量名)
	return IDENT
}
